package org.msz.keycloak;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;

public class HttpServletRequestInfo {
    public final String requesterUserID;
    public final String requesterHost;
    public final int requesterPort;
    public final String requestURI;
    public final String queryString;
    public final String localHost;
    public MediaType contentType;

    private HttpServletRequestInfo(HttpServletRequest request) {
        requesterUserID = KeycloakContext.valueOf(request).getUserName();
        requesterHost = realRequestHost(request);
        requesterPort = request.getRemotePort();
        requestURI = request.getRequestURL().toString();
        queryString = request.getQueryString();
        localHost = request.getServerName();
    }

    private HttpServletRequestInfo(String requesterUserID, String requesterHost, String requestURI) {
        this.requesterUserID = requesterUserID;
        this.requesterHost = requesterHost;
        this.requesterPort = 0;
        this.requestURI = requestURI;
        this.queryString = null;
        this.localHost = hostOfURI(requestURI);
    }

    public static HttpServletRequestInfo valueOf(HttpServletRequest request) {
        return new HttpServletRequestInfo(request);
    }

    public static HttpServletRequestInfo valueOf(String requesterUserID, String requesterHost, String requestURI) {
        return requestURI != null
                ? new HttpServletRequestInfo(requesterUserID, requesterHost, requestURI)
                : null;
    }

    private static String hostOfURI(String requestURI) {
        try {
            int beginIndex = requestURI.indexOf(':') + 1;
            while (requestURI.charAt(++beginIndex) == '/') ;
            int endIndex = beginIndex;
            char ch;
            while ((ch = requestURI.charAt(endIndex)) != '/' && ch != ':') endIndex++;
            return requestURI.substring(beginIndex, endIndex);
        } catch (IndexOutOfBoundsException e) {
            return null;
        }
    }

    public MediaType getContentType() {
        return contentType;
    }

    public HttpServletRequestInfo setContentType(HttpHeaders headers) {
        this.contentType = headers.getMediaType();
        return this;
    }

    @Override
    public String toString() {
        return "HttpServletRequestInfo[requesterUserID=" + requesterUserID
                + ", requesterHost=" + requesterHost
                + ", requesterPort=" + requesterPort
                + ", requesterURI=" + requestURI
                + ", queryString=" + queryString
                + ", localHost=" + localHost
                + "]";
    }

    public String realRequestHost(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && xForwardedFor.length() > 0) {
            return xForwardedFor.split(",")[0].trim();
        }
        // 如果 X-Forwarded-For 头部不存在，则读取 X-Real-IP 头部来获取真实 IP 地址
        String xRealIP = request.getHeader("X-Real-IP");
        if (xRealIP != null && xRealIP.length() > 0) {
            return xRealIP;
        }
        return request.getRemoteHost();
    }
}
